package logic

import (
	"container/ring"
	"github.com/spf13/viper"
)

// 离线处理器
type offlineProcessor struct {
	n int

	//保存所有用户最近的 n 条消息
	recentRing *ring.Ring

	//保存某个用户的离线消息（n 条）
	userRing map[string]*ring.Ring
}

// OfflineProcessor 对外提供一个单实例
var OfflineProcessor = newOfflineProcessor()

func newOfflineProcessor() *offlineProcessor {
	n := viper.GetInt("offline-num")

	return &offlineProcessor{
		n:          n,
		recentRing: ring.New(n),
		userRing:   make(map[string]*ring.Ring),
	}
}

// Save 存离线消息
func (o *offlineProcessor) Save(msg *Message) {
	if msg.Type != MsgTypeNormal {
		return
	}
	o.recentRing.Value = msg
	o.recentRing = o.recentRing.Next()

	for _, nickname := range msg.Ats {
		nickname = nickname[1:]
		var (
			r  *ring.Ring
			ok bool
		)
		if r, ok = o.userRing[nickname]; !ok {
			r = ring.New(o.n)
		}
		r.Value = msg
		o.userRing[nickname] = r.Next()
	}
}

// Send 用户离线后，再次进入聊天室时取消息
func (o *offlineProcessor) Send(user *User) {
	//遍历最近消息，发送给用户
	o.recentRing.Do(func(value any) {
		if value != nil {
			user.MessageChannel <- value.(*Message)
		}
	})

	//如果用户是新用户
	if user.IsNew {
		return
	}
	//如果用户不是新用户
	//查询是否有 @ 该用户的消息
	if r, ok := o.userRing[user.NickName]; ok {
		r.Do(func(value any) {
			//有消息则发送给该用户
			if value != nil {
				user.MessageChannel <- value.(*Message)
			}
		})
		//再将这些消息删除
		//因为最近的消息是所有用户共享的，所以不能删除；而 @ 用户的消息是用户独有的，所以可以删除
		delete(o.userRing, user.NickName)
	}
}
